package 多线程.AtomicInteger原理用法;
import java.util.function.IntUnaryOperator;
import java.util.function.IntBinaryOperator;
import sun.misc.Unsafe;

/**
 * 可以自动更新的int值。有关原子变量属性的描述，请参阅atomic包规范。
 * AtomicInteger用于诸如自动递增计数器之类的应用程序，不能用作Integer的替代品。
 * 但是，这个类扩展了Number，以允许处理基于数字的类的工具和实用程序进行统一访问。
*/
public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // 获取Unsafe实例，设置为使用Unsafe.compareAndSwapInt进行更新
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // 存放变量value的偏移量 
    private static final long valueOffset;

    static {
        try {
            // 获取value在AtomicInteger中的偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // 实际变量值，被声明为volatile是为了保证多线程下的内存可见性
    private volatile int value;

    /**
     * 用给定的初始值创建一个新的AtomicInteger。
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    /**
     * 创建一个初始值为0的新AtomicInteger。
     */
    public AtomicInteger() {
    }

    /**
     * 获取当前值
     */
    public final int get() {
        return value;
    }

    /**
     * 设置为给定的值。
     */
    public final void set(int newValue) {
        value = newValue;
    }

    /**
     * 最终设置为给定值。
     */
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

    /**
     * 自动设置为给定值并返回旧值。
     */
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }

    /**
     * 如果当前值==期望值，则自动将值设置为给定的更新值。
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 如果当前值==期望值，则自动将值设置为给定的更新值。
     * 可能会错误地失败，并且不提供排序保证，因此很少作为compareAndSet的合适替代。
     */
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 将当前值自动加1。
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

    /**
     * 将当前值自动减1。
     */
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

    /**
     * 自动将给定值添加到当前值。
     */
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }

    /**
     * 将当前值自动加1。
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    /**
     * 将当前值自动减1。
     */
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }

    /**
     * 自动将给定值添加到当前值。
     */
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

    /**
     * 使用应用给定函数的结果自动更新当前值，返回前一个值。
     * 该函数应该没有副作用，因为当尝试更新由于线程之间的争用而失败时，可以重新应用它。
     */
    public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * 使用应用给定函数的结果自动更新当前值，并返回更新后的值。
     * 该函数应该没有副作用，因为当尝试更新由于线程之间的争用而失败时，可以重新应用它。
     */
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * 使用对当前值和给定值应用给定函数的结果自动更新当前值，并返回前一个值。
     * 该函数应该没有副作用，因为当尝试更新由于线程之间的争用而失败时，可以重新应用它。
     * 应用该函数时，当前值作为第一个参数，给定的更新作为第二个参数。
     */
    public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * 使用将给定函数应用于当前值和给定值的结果自动更新当前值，并返回更新后的值。
     * 该函数应该没有副作用，因为当尝试更新由于线程之间的争用而失败时，可以重新应用它。
     * 应用该函数时，当前值作为第一个参数，给定的更新作为第二个参数。
     */
    public final int accumulateAndGet(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * 返回当前值的字符串表示形式。
     */
    public String toString() {
        return Integer.toString(get());
    }

    /**
     * 将AtomicInteger的值返回为int类型。
     */
    public int intValue() {
        return get();
    }

    /**
     * 在进行扩展原语转换后，返回此AtomicInteger的值为long类型。
     */
    public long longValue() {
        return (long)get();
    }

    /**
     * 在进行扩展原语转换后，返回此AtomicInteger的值为float类型。
     */
    public float floatValue() {
        return (float)get();
    }

    /**
     * 在进行扩展原语转换后，返回此AtomicInteger的值为double类型。
     */
    public double doubleValue() {
        return (double)get();
    }

}
